﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using Thread = System.Threading.Tasks;
using Microsoft.Practices.Unity;
using Infrastucture;
using Infrastucture.Collections;
using TimeSplicerModule.Factories;
using TimeSplicerModule.DomainModels;
using TimeSplicerModule.Security;
using TimeSplicerModule.ViewModels;

namespace TimeSplicerModule.Services
{
    public partial class ProjectService : IProjectService
    {
        public ProjectModel Get(Guid id)
        {
            // if role is less than pm than stuff will have to be hidden, diabled
            _session = _container.Resolve<ISession>();

            var model = _projectFactory.Get(x => x.ProjectGuid == id);

            model.Status = _session.Statuses.FirstOrDefault(x => x.StatusGuid == model.StatusGuid); //_statusFactory.Get(x => x.StatusGuid == model.StatusGuid);

            model.Categories = _categoryService.GetSelectableProjectCategories();
            model.Category = model.Categories.FirstOrDefault(x => x.CategoryGuid == model.CategoryGuid);

            model.Priorities = _session.Priorities; //_priorityFactory.GetList();
            model.Priority = model.Priorities.FirstOrDefault(x => x.PriorityGuid == model.ProjectGuid);

            model.TaskStatuses = _session.Statuses.Where(x => x.IsTaskStatus && x.IsActive).ToList(); //_statusFactory.GetList(x => x.IsTaskStatus && x.IsActive);

            model.ProjectManagers = _userService.GetSelectableProjectManagers();
            model.ProjectManager = model.ProjectManagers.FirstOrDefault(x => x.UserGuid == model.ProjectManagerGuid);

            // need to get users
            var users = _userFactory.GetList();
            var statuses = _session.Statuses; //_statusFactory.GetList();

            model.Users = users;
            model.ProjectRoles = _projectRoleFactory.GetList();
            model.ProjectUsers = _projectUserFactory.GetList(users, model.ProjectRoles)
                .Where(x => x.ProjectGuid == model.ProjectGuid).ToList();
            model.ObservableProjectUsers = model.ProjectUsers.ToObservableCollection();
            model.CreatedBy = users.FirstOrDefault(x => x.UserGuid == model.CreatedByGuid);
            model.Tasks = _taskFactory.GetList().Where(x => x.ProjectGuid == model.ProjectGuid).ToList();
            model.Tasks.ForEach(x => 
                { 
                    x.Project = model; 
                    x.Status = statuses.FirstOrDefault(s => s.StatusGuid == x.StatusGuid); 
                    //var stamps = _timestampFactory.GetList(t => t.TaskGuid == x.TaskGuid);
                    //x.Hours = getTaskHours(stamps);
                });
            model.FilteredTasks = model.Tasks.Where(x => x.AssignedToGuid == _session.User.UserGuid).ToObservableCollection();

            // somwhere will need to limit user view if not PM
            // need to set up filtered tasks
            

            model.SelectedTaskUserGuid = _session.User.UserGuid;
           // model.Hours = getProjectHours(model.Tasks);

            return model;
        }

        public ProjectModel Save(ProjectModel project)
        {
            _session = _container.Resolve<ISession>();

            bool isNew = project.ProjectGuid == Guid.Empty;

            var projectUsers = project.ProjectUsers;
            project = _projectFactory.Upsert(project);

            // if guid is empty then add PM to use  list
            if (isNew)
            {
                // see if user pm is added as pm role first
                var existing = projectUsers.FirstOrDefault(x => x.UserGuid == project.ProjectManagerGuid);
                var pm = _projectRoleFactory.Get(x => x.Name == "Project Manager");

                if (existing == null && pm != null)
                {
                    var user = new ProjectUserModel { ProjectGuid = project.ProjectGuid, UserGuid = project.ProjectManagerGuid, ProjectRoleGuid = pm.ProjectRoleGuid };
                    projectUsers.Add(user);
                    //_projectUserFactory.Upsert(user);
                }
            }

            // insert project users
            foreach (var u in projectUsers)
            {
                u.ProjectGuid = project.ProjectGuid;

                _projectUserFactory.Upsert(u);
            }


            if (project.Users == null)
                project.Users = _userFactory.GetList();

            if (project.ProjectRoles == null)
                project.ProjectRoles = _projectRoleFactory.GetList();

            project.ProjectUsers = _projectUserFactory.GetList(project.Users, project.ProjectRoles);

            return project;
        }

        public List<ProjectModel> GetList(UserModel user)
        {
            List<ProjectModel> projects = new List<ProjectModel>();

            var projectUsers = _projectUserFactory.GetList(x => x.UserGuid == user.UserGuid);
            var distictIds = projectUsers.Select(x => x.ProjectGuid).ToList();

            foreach (var i in distictIds)
            {
                var p = Get(i);
                projects.Add(p);
            }

            return projects;
        }

        public List<ProjectModel> GetMyProjects()
        {
            _session = _container.Resolve<ISession>();
            List<ProjectModel> projects = new List<ProjectModel>();

            // this will be any project they are the overall pm in or were added as a user
            var myProjectUserInstances = _projectUserFactory.GetList(x => x.UserGuid == _session.User.UserGuid);

            // for each user get the project
            foreach (var i in myProjectUserInstances)
            {
                var p = Get(i.ProjectGuid);
                projects.Add(p);
            }

            return projects;
        }
        public List<ProjectModel> GetMyProjects(StatusModel byStatus)
        {
            // this will be any project they are the overall pm in or were added as a user
            // except limited by status

            _session = _container.Resolve<ISession>();



            return GetMyProjects().Where(x => x.StatusGuid == byStatus.StatusGuid).ToList();
        }
        public List<ProjectModel> GetMyTeamUserProjects()
        {
            _session = _container.Resolve<ISession>();
            List<ProjectModel> projects = new List<ProjectModel>();

            // get all projects that you can see that are on your team
            // so project user and lower on the hierarchy
            var myTeam = _session.User.Team;
            //var users = _userFactory.GetList();
            var teamUsers = _userService.GetViewableUsers().Where(x => x.TeamGuid == myTeam.TeamGuid).ToList();

            // get all projects that each of these users are associated with users on my team
            foreach (var u in teamUsers)
            {
                var p = GetList(u);
                projects.AddRange(p);
            }

            return projects;
        }
        public List<ProjectModel> GetModelByTeam(Guid teamGuid)
        {
            // should probably limit this call only to devs, principal
            _session = _container.Resolve<ISession>();

            // get all projects that each member of the selected team are involved with

            // get users by team

            

            throw new NotImplementedException();
        }


        public void UpdateProjectStatus(Guid projectGuid, StatusModel status)
        {
            var proj = _projectFactory.Get(x => x.ProjectGuid == projectGuid);

            if (proj.StatusGuid != status.StatusGuid)
            {
                proj.StatusGuid = status.StatusGuid;

                proj = _projectFactory.Upsert(proj);
            }
        }


        public List<ProjectModel> GetList(List<UserModel> users)
        {
            List<ProjectModel> projects = new List<ProjectModel>();

            foreach (var u in users)
            {
                var projs = GetList(u);

                foreach (var p in projs)
                {
                    var existing = projects.FirstOrDefault(x => x.ProjectGuid == p.ProjectGuid);

                    if (existing == null)
                        projects.Add(p);
                }
            }

            return projects;
        }
    }
}
